package org.example.Imp;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import exam.dao.ExamDao;
import exam.dao.StudentDao;
import exam.dao.Student_ExamDao;
import org.example.ExamService;
import org.example.StudentService;
import org.example.Student_ExamService;
import org.example.domain.Exam;
import org.example.domain.Student;
import org.example.domain.Student_Exam;
import org.example.dto.ExamPaperDTO;
import org.example.dto.ExamStudentDTO;
import org.example.pageParam.CommonData;
import org.example.vo.ExamBindClassVO;
import org.example.vo.PageVO;
import org.example.vo.QuestionVO;
import org.example.vo.StudentExamAnswerVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class ExamServiceImp implements ExamService {
    @Autowired
    private Student_ExamService student_examService;
    @Autowired
    private ExamDao examDao;
    @Autowired
    private Student_ExamDao student_examDao;
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private StudentService studentService;
    @Override
    public PageVO queryExam(int page,int count,Map<String, Object> map) {
        PageHelper.startPage(page,count);
        List<Exam> query = examDao.query(map);
        PageInfo pageInfo = new PageInfo(query);
        PageVO pageVO = new PageVO();
        pageVO.setParams(pageInfo.getList());
        pageVO.setFilterName(map.get("name")+"-"+map.get("type")+"-"+map.get("status")+"-"+map.get("start_time")+"-"+map.get("edn_time"));
        pageVO.setPage(pageInfo.getPageNum());
        pageVO.setCount(pageInfo.getPageSize());
        pageVO.setStart(page*count);
        pageVO.setLength(count);
        pageVO.setRealPage(pageInfo.getPages());
        pageVO.setTotal((int)pageInfo.getTotal());
        pageVO.setPageStart(pageInfo.getPageNum());
        pageVO.setPageEnd(pageInfo.getPages());
        return pageVO;
    }

    @Override
    public boolean addSave(Exam exam) {
        Boolean result = null;
        try{
            examDao.addSave(exam);
            result = true;
        }catch (Exception e){
            e.printStackTrace();
            result = false;
        }
        return result;
    }

    @Override
    public Exam selectExamById(Long id) {
        return examDao.selectById(id);
    }

    @Override
    public boolean updateExamName(Long id, String name) {
        Boolean result = null;
        try{
            examDao.updateExamName(id,name);
            result = true;
        }catch (Exception e){
            result = false;
        }
        return result;
    }

    /**
     * 方法中的小算法 我用了很笨的方法  很多循环  我知道很不好 但是，暂时想不到好办法
     * 因为我们在最初的设计中没有考试循环依赖的问题 导致spring 和 springmvc配置中无法获取对应的包名 导致无法配置scan 所以 无法产生代理对象 难受 可能有其他方法 我学的不好
     * 所以这个方法没有处理事务  有异常还是会存储到数据库
     * @param exam
     * @param studentCodeCache
     */

    @Override
    public void editSave(Exam exam, Map<String, String> studentCodeCache) {
        //先存储exam的一些基本信息
        examDao.editSave(exam);


        //当前考试需要的关联学生  首先需要从数据库中查到当前exam关联的所有学生
        List<Student_Exam> student_exams = student_examDao.selectStudentByExamId(exam.getId());
        //如果是对当前模板的第一次保存 student_exams的length为0 正常存储 如果length不为0说明需要做一些删除或者一些添加处理
        if (student_exams.size()==0){
            //因为存储student_exam需要的是studentId 但是缓存的是学号 所以需要查出学生
            //这里有个问题 什么呢？ 如果要存储到student_exam中 需要一个字段 exam_group 这个是cache中的key
            //需要按照班级获取学生存储
            Iterator<String> iterator = studentCodeCache.keySet().iterator();
            List<Student_Exam> studentExams = new ArrayList<>();
            while (iterator.hasNext()){
                String key = iterator.next();
                String value = studentCodeCache.get(key);
                List<Student> studentList;
                if (value.equals("All")){
                    String classStudentCodes = studentService.selectClassAllStudentCode(key);
                    String[] codes1 = classStudentCodes.split(",");
                    studentList = studentDao.selectStudentByCodes(Arrays.asList(codes1));
                }else if (value.startsWith("x,")){
                    String[] codes2 = value.replace("x,", "").split(",");
                    studentList = studentDao.selectStudentByCodes(Arrays.asList(codes2));
                }else {
                    String[] codes3 = value.split(",");
                    studentList = studentDao.selectStudentByCodes(Arrays.asList(codes3));
                }
                for (int i = 0;i<studentList.size();i++){
                    Student_Exam student_exam = new Student_Exam();
                    Student student = studentList.get(i);
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(student.getId());
                    student_exam.setExam_group(key);
                    student_exam.setStatus("未考试");
                    studentExams.add(student_exam);
                }
            }
            student_examDao.saves(studentExams);
            return;
        }
        //数据库存储当前模板的关联学生 需要做删除或者添加操作
        //我们可以将查出来的关联学生 按照exam_group组装起来 然后 按照cache进行筛选
        Map<String,Set<String>> databaseCache = new HashMap<>();
        Map<String,Set<String>> currentCache = new HashMap<>();
        for (int i = 0;i<student_exams.size();i++){
            Student_Exam student_exam = student_exams.get(i);//一个单独的student_exam
            String exam_group = student_exam.getExam_group();
            Set<String> set = databaseCache.get(exam_group);
            if (set==null){
                //表示当前map中不存在当前考试组 需要将当前考试组添加到map中  需要创建一个新的set
                Set<String> temp = new HashSet<>();
                temp.add(student_exam.getStudent_id().toString());
                databaseCache.put(exam_group,temp);
                continue;
            }
            set.add(student_exam.getStudent_id().toString());
        }
        //循环执行完 databaseCache中就存储班级对应的set set中是学生id
        //下面处理缓存中的codes
        Iterator<String> iterator = studentCodeCache.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            String value = studentCodeCache.get(key);
            String ids ;
            if (value.equals("All")){
                ids = studentDao.selectClassAllStudentId(key);
            }else if (value.startsWith("x,")){
                String[] codes2 = value.replace("x,", "").split(",");
                ids= studentDao.selectClassIdsByCodes(Arrays.asList(codes2));
            }else {
                String[] codes3 = value.split(",");
                ids = studentDao.selectClassIdsByCodes(Arrays.asList(codes3));
            }
            Set<String> set = currentCache.get(key);
            if (set==null){
                Set<String> setIds = new HashSet<>();
                setIds.addAll(Arrays.asList(ids.split(",")));
                currentCache.put(key,setIds);
                continue;
            }
            set.addAll(Arrays.asList(ids.split(",")));
        }
        //到此为止两个map中都存储这班级对应的id 现在需要排除了 可能需要添加 可能需要删除
        Set<Student_Exam> addSet = new HashSet<>();
        Set<Student_Exam> removeSet = new HashSet<>();
        Set<String> bigBox = new HashSet<>();//用来
        //用size的大小作为迭代的对象 长度大 作为迭代对象（可以判断所以班级）  但是长度一样时
        Iterator<String> iterator_1 = currentCache.keySet().iterator();
        while (iterator_1.hasNext()){
            String key = iterator_1.next();
            Set<String> currentSet = currentCache.get(key);
            Set<String> databaseSet = databaseCache.get(key);
            if (databaseSet==null){
                //说明当前cache班级的学生全部需要添加到数据库中
                Iterator<String> iterator2 = currentSet.iterator();
                while (iterator2.hasNext()){
                    String currentId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(currentId));
                    student_exam.setExam_group(key);
                    student_exam.setStatus("未考试");
                    student_exam.setStart_time(exam.getStart_time());
                    student_exam.setEnd_time(exam.getEnd_time());
                    addSet.add(student_exam);
                }
                continue;
            }
            if (currentSet==null){
                //说明数据库存在当前班级  但是缓存中不存在 需要从数据库中删除整个班级
                Iterator<String> iterator2 = databaseSet.iterator();
                while (iterator2.hasNext()){
                    String currentId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(currentId));
                    student_exam.setExam_group(key);
                    removeSet.add(student_exam);
                }
                continue;
            }
            //数据库存在当前缓存中的班级  需要判断是否增减
            //我们可以 用curr-database 剩下的表示需要添加   database-curr 剩下的表示需要移除   这两种情况如果剩下的size为0 表示不需要添加和删除
            bigBox.addAll(currentSet);
            bigBox.removeAll(databaseSet);
            //需要做添加
            if (bigBox.size()>0){
                Iterator<String> iterator2 = bigBox.iterator();
                while (iterator2.hasNext()){
                    String addId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(addId));
                    student_exam.setExam_group(key);
                    student_exam.setStatus("未考试");
                    student_exam.setStart_time(exam.getStart_time());
                    student_exam.setEnd_time(exam.getEnd_time());
                    addSet.add(student_exam);
                }
            }
            if (bigBox.size()==0){
                //可能是123 - 123  不处理  12 - 123 需要做删除
                bigBox.clear();
                bigBox.addAll(currentSet);
                bigBox.addAll(databaseSet);
                if (bigBox.size()!=currentSet.size()+databaseSet.size()){
                    //database需要删除
                    bigBox.clear();
                    bigBox.addAll(databaseSet);
                    bigBox.removeAll(currentSet);
                    Iterator<String> iterator2 = bigBox.iterator();
                    while (iterator2.hasNext()){
                        String addId = iterator2.next();
                        Student_Exam student_exam = new Student_Exam();
                        student_exam.setExam_id(exam.getId());
                        student_exam.setStudent_id(Long.parseLong(addId));
                        student_exam.setExam_group(key);
                        removeSet.add(student_exam);
                    }
                }
            }
            bigBox.clear();
            bigBox.addAll(databaseSet);
            bigBox.removeAll(currentSet);
            if (bigBox.size()>0){
                //需要做删除
                Iterator<String> iterator2 = bigBox.iterator();
                while (iterator2.hasNext()){
                    String addId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(addId));
                    student_exam.setExam_group(key);
                    removeSet.add(student_exam);
                }

            }
            if (bigBox.size()==0){
                //可能是123 - 123  不处理  12 - 123 需要做添加
                bigBox.clear();
                bigBox.addAll(currentSet);
                bigBox.addAll(databaseSet);
                if (bigBox.size()!=currentSet.size()+databaseSet.size()){
                    //database需要添加
                    bigBox.clear();
                    bigBox.addAll(currentSet);
                    bigBox.removeAll(databaseSet);
                    Iterator<String> iterator2 = bigBox.iterator();
                    while (iterator2.hasNext()){
                        String addId = iterator2.next();
                        Student_Exam student_exam = new Student_Exam();
                        student_exam.setExam_id(exam.getId());
                        student_exam.setStudent_id(Long.parseLong(addId));
                        student_exam.setExam_group(key);
                        addSet.add(student_exam);
                    }
                }
            }
            bigBox.clear();
        }
        Iterator<String> iterator_2 = databaseCache.keySet().iterator();
        while (iterator_2.hasNext()){
            String key = iterator_2.next();
            Set<String> currentSet = currentCache.get(key);
            Set<String> databaseSet = databaseCache.get(key);
            if (databaseSet==null){
                //说明当前cache班级的学生全部需要添加到数据库中
                Iterator<String> iterator2 = currentSet.iterator();
                while (iterator2.hasNext()){
                    String currentId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(currentId));
                    student_exam.setExam_group(key);
                    student_exam.setStatus("未考试");
                    student_exam.setStart_time(exam.getStart_time());
                    student_exam.setEnd_time(exam.getEnd_time());
                    addSet.add(student_exam);
                }
                continue;
            }
            if (currentSet==null){
                //说明数据库存在当前班级  但是缓存中不存在 需要从数据库中删除整个班级
                Iterator<String> iterator2 = databaseSet.iterator();
                while (iterator2.hasNext()){
                    String currentId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(currentId));
                    student_exam.setExam_group(key);
                    removeSet.add(student_exam);
                }
                continue;
            }
            //数据库存在当前缓存中的班级  需要判断是否增减
            //我们可以 用curr-database 剩下的表示需要添加   database-curr 剩下的表示需要移除   这两种情况如果剩下的size为0 表示不需要添加和删除
            bigBox.addAll(currentSet);
            bigBox.removeAll(databaseSet);
            //需要做添加
            if (bigBox.size()>0){
                Iterator<String> iterator2 = bigBox.iterator();
                while (iterator2.hasNext()){
                    String addId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(addId));
                    student_exam.setExam_group(key);
                    student_exam.setStatus("未考试");
                    student_exam.setStart_time(exam.getStart_time());
                    student_exam.setEnd_time(exam.getEnd_time());
                    addSet.add(student_exam);
                }
            }
            if (bigBox.size()==0){
                //可能是123 - 123  不处理  12 - 123 需要做删除
                bigBox.clear();
                bigBox.addAll(currentSet);
                bigBox.addAll(databaseSet);
                if (bigBox.size()!=currentSet.size()+databaseSet.size()){
                    //database需要删除
                    bigBox.clear();
                    bigBox.addAll(databaseSet);
                    bigBox.removeAll(currentSet);
                    Iterator<String> iterator2 = bigBox.iterator();
                    while (iterator2.hasNext()){
                        String addId = iterator2.next();
                        Student_Exam student_exam = new Student_Exam();
                        student_exam.setExam_id(exam.getId());
                        student_exam.setStudent_id(Long.parseLong(addId));
                        student_exam.setExam_group(key);
                        removeSet.add(student_exam);
                    }
                }
            }
            bigBox.clear();
            bigBox.addAll(databaseSet);
            bigBox.removeAll(currentSet);
            if (bigBox.size()>0){
                //需要做删除
                Iterator<String> iterator2 = bigBox.iterator();
                while (iterator2.hasNext()){
                    String addId = iterator2.next();
                    Student_Exam student_exam = new Student_Exam();
                    student_exam.setExam_id(exam.getId());
                    student_exam.setStudent_id(Long.parseLong(addId));
                    student_exam.setExam_group(key);
                    removeSet.add(student_exam);
                }

            }
            if (bigBox.size()==0){
                //可能是123 - 123  不处理  12 - 123 需要做添加
                bigBox.clear();
                bigBox.addAll(currentSet);
                bigBox.addAll(databaseSet);
                if (bigBox.size()!=currentSet.size()+databaseSet.size()){
                    //database需要添加
                    bigBox.clear();
                    bigBox.addAll(currentSet);
                    bigBox.removeAll(databaseSet);
                    Iterator<String> iterator2 = bigBox.iterator();
                    while (iterator2.hasNext()){
                        String addId = iterator2.next();
                        Student_Exam student_exam = new Student_Exam();
                        student_exam.setExam_id(exam.getId());
                        student_exam.setStudent_id(Long.parseLong(addId));
                        student_exam.setExam_group(key);
                        addSet.add(student_exam);
                    }
                }
            }
            bigBox.clear();
        }
        //到此为止 删除 添加都在removeSet中addSet
        if (removeSet.size()>0){
            //有数据需要删除
            examDao.remove(new ArrayList<>(removeSet));
        }
        if (addSet.size()>0){
            //有数据需要添加
            examDao.add(new ArrayList<>(addSet));
        }

    }

    @Override
    public void add(List<Student_Exam> student_examList) {
        examDao.add(student_examList);
    }

    @Override
    public void remove(List<Student_Exam> student_examList) {
        examDao.remove(student_examList);
    }

    @Override
    public List<ExamBindClassVO> selectBindClassByExamId(Long examId) {
        return examDao.selectBindClassById(examId);
    }

    @Override
    public void removeExamByExamId(Long examId) {
        examDao.removeExam(examId);
    }
    @Override
    public void releaseExam(Long examId) {
        examDao.releaseExam(examId);
    }
    //====学生模块的查询

    @Override
    public List<Map<String, String>> selectExamByStudentId(Map<String,Object> param) {
        return examDao.selectExamByStudentId(param);
    }

    @Override
    public void updateExamStatus(Long examId, String examStatus) {
        //这里可能出现多线程问题 多个学生同时考试同时修改考试状态
        synchronized ("updateExamStatus"){
            examDao.updateExamStatus(examId,examStatus);
        }
    }

    @Override
    public List<ExamPaperDTO> selectFinishExamClass(Long examId) {
        return examDao.selectFinishExamClass(examId);
    }

    @Override
    public List<ExamStudentDTO> selectExamStudentList(Long examId, String className) {
        return examDao.selectExamStudentList(examId,className);
    }

    @Override
    public void handleOneStudentExamPaperScore(Student_Exam student_exam) {
        //首先获取当前学生的自定义答案
        StudentExamAnswerVO studentExamAnswerVO = student_examService.parseExamAnswer(student_exam);
        //获取卷子的试题
        List<QuestionVO> questionVOS = student_examService.generateExamPaper(student_exam.getPage_path());
        int score = 0;
        StringBuilder score_str = new StringBuilder();
        if (student_exam.getStatus().equals("缺考")){
            for (int i = 0;i<questionVOS.size();i++){
                score_str.append(0+CommonData.COMMON_NORMAL_SEPARATOR);
            }

        }else {
            if (studentExamAnswerVO.getAnswers().size()==0){
                //表示进入考试了 但是没有填写任何答案
                for (int i = 0;i<questionVOS.size();i++){
                    score_str.append(0+CommonData.COMMON_NORMAL_SEPARATOR);
                }
            }else {
                i:for (int i  = 0;i<questionVOS.size();i++){
                    Object selfAnswer = studentExamAnswerVO.getAnswers().get(i);
                    QuestionVO questionVO = questionVOS.get(i);
                    if (questionVO.getType().equals("单选题")){
                        String question1Answer = (String) selfAnswer;
                        if(!question1Answer.equals("no")){
                            String[] answers = questionVO.getAnswers();

                            for (String answer : answers){
                                if (answer!=null){
                                    //这是当前试卷的答案
                                    if (answer.equals(question1Answer)){
                                        //这道单选题选中了
                                        score = score + questionVO.getScore();
                                        score_str.append(questionVO.getScore()+ CommonData.COMMON_NORMAL_SEPARATOR);
                                    }else {
                                        score_str.append(0+ CommonData.COMMON_NORMAL_SEPARATOR);
                                    }
                                }
                            }
                        }
                    }
                    if (questionVO.getType().equals("多选题")){
                        List<String> question2Answer = (List<String>) selfAnswer;
                        boolean checked = false;//用来判断是否做过多选题
                        j:for (int j = 0;j<question2Answer.size();j++){
                            String tempAnswer = question2Answer.get(j);
                            if (!tempAnswer.equals("")){
                                //只要有一个答案 就表示你做过当前试题  我们就可以算分数
                                checked = true;
                                break j;
                            }
                        }
                        if (checked){
                            boolean right = false;//用来判断做对多选题
                            //做过
                            String[] tempQuestion2Answer = questionVO.getAnswers();
                            //首先判断 我们选择的答案 个数 预标准答案个数是否一致
                            int selfAnswerCount = 0;//当前多选题我们选择的答案
                            int examAnswerCount = 0;//当前多选题标准答案
                            for (String tempSelfAnswer : question2Answer){
                                if (!tempSelfAnswer.equals(" ")){
                                    //表示选择过一个答案
                                    selfAnswerCount = selfAnswerCount +1;
                                }
                            }
                            for (String tempExamAnswer : tempQuestion2Answer){
                                if (tempExamAnswer!=null){
                                    examAnswerCount = examAnswerCount +1;
                                }
                            }
                            if (selfAnswerCount != examAnswerCount){
                                //答案个数预标准答案不一致
                                continue i;
                            }
                            //个数选对 然后判断选择的顺序
                            boolean result = true;//用来判断预答案是否一致
                            j:for (int j = 0;j<tempQuestion2Answer.length;j++){
                                //标准答案中存储格式 [null,B,C,D]  自定义答案 [" ",B," "," "]
                                String examQuestion2Answer = tempQuestion2Answer[j];
                                String selfQuestion2Answer = question2Answer.get(j);
                                if (examQuestion2Answer==null){
                                    if (!selfQuestion2Answer.equals(" ")){
                                        //表示当前选项都没有选择
                                        result = false;
                                        break j;
                                    }
                                }else {
                                    //表示这是其中一个选项  判断一下 我是否选择了
                                    if (!examQuestion2Answer.equals(selfQuestion2Answer)){
                                        result = false;
                                        break j;
                                    }
                                }
                            }
                            if (result){
                                //表示当前多选题正确
                                score = score + questionVO.getScore();
                                score_str.append(questionVO.getScore()+ CommonData.COMMON_NORMAL_SEPARATOR);
                            }else {
                                score_str.append(0+ CommonData.COMMON_NORMAL_SEPARATOR);
                            }
                        }
                    }
                    if (questionVO.getType().equals("判断题")){
                        String question3Answer = (String)selfAnswer;
                        if (question3Answer.equals("no")){
                            continue i;
                        }
                        String examQuestion3Answer = questionVO.getAnswers()[0];
                        if (question3Answer.equals(examQuestion3Answer)){
                            score = score + questionVO.getScore();
                            score_str.append(questionVO.getScore()+ CommonData.COMMON_NORMAL_SEPARATOR);
                        }else {
                            score_str.append(0+ CommonData.COMMON_NORMAL_SEPARATOR);
                        }
                    }
                    if (questionVO.getType().equals("填空题")){

                    }
                    if (questionVO.getType().equals("综合题")){

                    }
                }
            }

        }
        //更新一下当前计算的分数
        student_examService.studentExamScoreSave(student_exam.getExam_id(),student_exam.getStudent_id(),score);
        //更新一下简单判断多选 的得分字符串
        //如果提交考试 到这里只会处理单选题 多选题 判断题 的分数保存 用于页面展示  但是为了前端不麻烦判断 填空和综合就0分代替 后续分数需要老师自行判断给分
        List<String> getScore =  Arrays.asList(score_str.toString().split(CommonData.COMMON_SEPARATOR));
        if (getScore.size()!=questionVOS.size()){
            //就是我们没有处理填空和综合的分值
            int loseScore = questionVOS.size() - getScore.size();
            for (int i = getScore.size();i<questionVOS.size();i++){
                score_str.append(0+CommonData.COMMON_NORMAL_SEPARATOR);
            }

        }
        if (student_exam.getYuliu2() == null){
            student_exam.setYuliu2(score_str.toString());
            //controller中避免再次与数据库交互获取对象
        }
        student_examService.studentExamScoreStrSave(student_exam.getExam_id(),student_exam.getStudent_id(),score_str.toString());
    }

    @Override
    public ExamStudentDTO selectOneExamStudent(Long examId, Long studentId) {
        return examDao.selectOneExamStudent(examId,studentId);
    }
    @Override
    public void examPaperSubmit(Long examId) {
        examDao.examPaperSubmit(examId);
    }

    @Override
    public List<Integer> selectStudentCurrYear(Long studentId) {
        return examDao.selectStudentCurrYear(studentId);
    }

    @Override
    public List<ExamPaperDTO> selectExamByYear(Long studentId, Integer year) {
        return examDao.selectExamByYear(studentId,year);
    }
}
